home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / mint / mntlb20 / lib / strftime.c < prev    next >
C/C++ Source or Header  |  1991-05-05  |  7KB  |  229 lines

  1. /*
  2.  * strftime: print formatted information about a given time
  3.  * Written by Eric R. Smith and placed in the public domain.
  4.  *
  5.  * With further modifications by Michal Jaegermann.
  6.  * Formats in SYSV_EXT from PD strftime source by Arnold Robins.
  7.  * 
  8.  */
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <time.h>
  13. #include <ctype.h>
  14. #include <string.h>
  15.  
  16. #define BIG_LEN 80
  17.  
  18. static int weeknumber __PROTO((const struct tm *timeptr, int firstweekday));
  19.  
  20.  
  21. extern char **_LC_Mth_name;     /* in setlocale.c */
  22. extern char **_LC_Day_name;
  23.  
  24. /*
  25.  * FIXME: I'm not sure what the formats for 'c', 'x', and 'X' should be
  26.  * for various locales, or even for the "C" locale. I've assumed that
  27.  * 'c' gives the same as asctime(), 'x' is e.g. Jan 01 1970, and
  28.  * 'X' is e.g. 12:20:37.
  29.  *
  30.  * I would venture that for "C" locale these formats are fine - mj.
  31.  */
  32.  
  33. size_t
  34. strftime(str, maxsize, fmt, ts)
  35.         char *str;
  36.         size_t maxsize;
  37.         const char *fmt;
  38.         const struct tm *ts;
  39. {
  40.         int    num = 0;
  41.         int     len = 0, n;
  42.         char    q;
  43.         char    buf[BIG_LEN], *putstr, *s;
  44.  
  45.         for(;;) {
  46.                 if (num >= maxsize) return 0;
  47.                 if (!(q = *fmt++))  break;
  48.                 if (q != '%') {
  49.                         *str++ = q;
  50.                         num++;
  51.                         continue;
  52.                 }
  53.                 if (!(q = *fmt++)) break;       /* get format command */
  54.  
  55. /* assume that sprintf will be used, with a variable length */
  56. /* this is the most common case, so it saves us some coding to do it here */
  57.                 putstr = buf;
  58.  
  59.                 switch(q) {
  60.                   case 'A':
  61.                   case 'a':
  62.           /*
  63.            * cases 'a' and 'b' are still wrong -
  64.            * in some locale short names do not have to be
  65.            * 3 characters wide - still works in North America.
  66.            */
  67.                     if (ts->tm_wday < 0 || ts->tm_wday > 6)
  68.                     putstr = "?";
  69.             else
  70.                     if ( 'A' == q)
  71.                         putstr = _LC_Day_name[ts->tm_wday];
  72.                 else
  73.                         sprintf(buf, "%-.3s",
  74.                         _LC_Day_name[ts->tm_wday]);
  75.                         break;
  76.                   case 'B':
  77.                   case 'b':
  78. #ifdef SYSV_EXT
  79.                   case 'h':    /* same as 'b' */
  80. #endif
  81.                     if (ts->tm_mon < 0 || ts->tm_mon > 11)
  82.                     putstr = "?";
  83.             else
  84.                     if ( 'B' == q)
  85.                         putstr = _LC_Mth_name[ts->tm_mon];
  86.                 else
  87.                         sprintf(buf, "%-.3s",
  88.                         _LC_Mth_name[ts->tm_mon]);
  89.                         break;
  90.                   case 'c':
  91.             /* this format should be set in setlocale.c */
  92.                         strftime(buf, sizeof buf, "%a %b %d %X %Y", ts);
  93.                         break;
  94.           case 'd':
  95.                         sprintf(buf, "%02d", ts->tm_mday);
  96.                         break;
  97.                   case 'H':
  98.                         sprintf(buf, "%02d", ts->tm_hour);
  99.                         break;
  100.                   case 'I':
  101.                         n = ts->tm_hour;
  102.                         if (n == 0) n = 12;
  103.             else if (n > 12) n -= 12;
  104.                         sprintf(buf, "%02d", n);
  105.                         break;
  106.                   case 'j':
  107.                         sprintf(buf, "%03d", ts->tm_yday + 1);
  108.                         break;
  109.                   case 'm':
  110.                         sprintf(buf, "%02d", ts->tm_mon + 1);
  111.                         break;
  112.                   case 'M':
  113.                         sprintf(buf, "%02d", ts->tm_min);
  114.                         break;
  115.                   case 'p':
  116.             /*
  117.              * this is wrong - strings "AM', "PM" are
  118.              * locale dependent
  119.              */
  120.                         putstr = (ts->tm_hour < 12) ? "AM" : "PM";
  121.                         break;
  122.                   case 'S':
  123.                         sprintf(buf, "%02d", ts->tm_sec);
  124.                         break;
  125.                   case 'U':  /* week of year - starting Sunday */
  126.             sprintf(buf, "%02d", weeknumber(ts, 0));
  127.                         break;
  128.                   case 'W': /* week of year - starting Monday */
  129.             sprintf(buf, "%02d", weeknumber(ts, 1));
  130.                         break;
  131.                   case 'w':
  132.                         sprintf(buf, "%d", ts->tm_wday);
  133.                         break;
  134.                   case 'x':
  135.                 /* once again - format may be locale dependent */ 
  136.                         strftime(buf, sizeof buf, "%b %d %Y", ts);
  137.                         break;
  138.                   case 'X':
  139.             /* same applies to this format as well */
  140.                         sprintf(buf, "%02d:%02d:%02d", ts->tm_hour,
  141.                                 ts->tm_min, ts->tm_sec);
  142.                         break;
  143.                   case 'y':
  144.                         sprintf(buf, "%02d", ts->tm_year % 100);
  145.                         break;
  146.           case 'Y':
  147.                         sprintf(buf, "%d", ts->tm_year + 1900);
  148.                         break;
  149.                   case 'Z':
  150.                         if (NULL != (s = getenv("TZ"))) {
  151.                 strcpy(buf, s);
  152.                 s = buf;
  153.                 if (ts->tm_isdst) {
  154.                     while (*s && isalpha(*s)) s++;
  155.                         while (*s && (isdigit(*s)||
  156.                               *s == '+'  ||
  157.                               *s == '-'  ||
  158.                               *s == ':')) {
  159.                             s++;
  160.                         };
  161.                         if (*s)
  162.                             putstr = s;
  163.                 }
  164.                 s = putstr;
  165.                 while (*s && isalpha(*s))
  166.                         s++;
  167.                 *s++ = 0;
  168.             }
  169.             else
  170.                     buf[0] = '\0'; /* empty string */
  171.                         break;
  172.                    case '%':
  173.                         putstr = "%";
  174.                         break;
  175. #ifdef SYSV_EXT
  176.            case 'n':    /* same as \n */
  177.             putstr = "\n";
  178.             break;
  179.            case 't':    /* same as \t */
  180.             putstr = "\n";
  181.             break;
  182.             break;
  183.            case 'D':    /* date as %m/%d/%y */
  184.             strftime(buf, sizeof buf, "%m/%d/%y", ts);
  185.             break;
  186.            case 'e':    /* day of month, blank padded */
  187.             sprintf(buf, "%2d", ts->tm_mday);
  188.             break;
  189.            case 'r':    /* time as %I:%M:%S %p */
  190.             strftime(buf, sizeof buf, "%I:%M:%S %p", ts);
  191.             break;
  192.            case 'R':    /* time as %H:%M */
  193.             strftime(buf, sizeof buf, "%H:%M", ts);
  194.             break;
  195.            case 'T':    /* time as %H:%M:%S */
  196.             strftime(buf, sizeof buf, "%H:%M:%S", ts);
  197.             break;
  198. #endif
  199.                 }
  200.  
  201.                 if (num + (len = strlen(putstr)) >= maxsize)
  202.                         return 0;
  203.  
  204.                 num += len;
  205.                 while (--len >= 0)
  206.                         *str++ = *putstr++;
  207.         }
  208.         *str = 0;
  209.         return (size_t) num;
  210. }
  211.  
  212. /* 
  213.  * What follows grabbed, with a small change, from PD source of strftime
  214.  * by Arnold Robins - arnold@audiofax.com
  215.  */
  216. /* With thanks and tip of the hatlo to ado@elsie.nci.nih.gov */
  217.  
  218. static int
  219. weeknumber(timeptr, firstweekday)
  220. const struct tm *timeptr;
  221. int firstweekday;
  222. /*
  223.  * firstweekday is 0 if starting in Sunday, non-zero if in Monday
  224.  */
  225. {
  226.     return (timeptr->tm_yday - timeptr->tm_wday +
  227.         (firstweekday ? (timeptr->tm_wday ? 8 : 1) : 7)) / 7;
  228. }
  229.